from starlette.requests import Request
from fastapi import APIRouter
from functools import wraps
import inspect
import typing as T
from ..server.service.local._UserHistoryCacheService import _ChatHistoryCacheService
from ..init.Global import user2chat_history, configuration, chatHistoryMap


# 不支持流式传输
def auto_chat_history_decorator(func: T.Callable):
    """
    用于自动处理聊天记录的获取和存储
    """
    if not callable(func):
        raise TypeError("decorator only works on callable objects")

    @wraps(func)
    async def wrapper(request: Request, *args, **kwargs):
        sessionId = request.headers.get("sessionId", None)
        if sessionId is not None:
            sessionId = int(sessionId)
            token = user2chat_history.set(
                await _ChatHistoryCacheService.get_history(sessionId)
            )
        if inspect.iscoroutinefunction(func):
            result = await func(*args, **kwargs)
        else:
            result = func(*args, **kwargs)
        if sessionId is not None:
            await _ChatHistoryCacheService.add_history(
                sessionId,
                user2chat_history.get()[-2:],
                configuration.redis.time,
            )
        return result

    original_signature = inspect.signature(func)
    parameters = list(original_signature.parameters.values())
    parameters = [
        inspect.Parameter(
            "request", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Request
        )
    ] + parameters

    wrapper.__signature__ = original_signature.replace(parameters=parameters)
    return wrapper


def mark(router: APIRouter, path: str, method: str, **kwargs):
    return getattr(router, method)(path, **kwargs)


def mark_chat_get(router: APIRouter, path: str, **kwargs):
    def decorator(func: T.Callable):
        if not callable(func):
            raise TypeError("decorator only works on callable objects")

        chatHistoryMap.add("GET", router.prefix + path, func)
        return mark(router, path, "get", **kwargs)(func)

    return decorator


def mark_chat_post(router: APIRouter, path: str, **kwargs):
    def decorator(func: T.Callable):
        if not callable(func):
            raise TypeError("decorator only works on callable objects")

        chatHistoryMap.add("POST", router.prefix + path, func)
        return mark(router, path, "post", **kwargs)(func)

    return decorator


def mark_chat_put(router: APIRouter, path: str, **kwargs):
    def decorator(func: T.Callable):
        if not callable(func):
            raise TypeError("decorator only works on callable objects")

        chatHistoryMap.add("PUT", router.prefix + path, func)
        return mark(router, path, "put", **kwargs)(func)

    return decorator


def mark_chat_delete(router: APIRouter, path: str, **kwargs):
    def decorator(func: T.Callable):
        if not callable(func):
            raise TypeError("decorator only works on callable objects")

        chatHistoryMap.add("DELETE", router.prefix + path, func)
        return mark(router, path, "delete", **kwargs)(func)

    return decorator


__all__ = [
    "mark_chat_get",
    "mark_chat_post",
    "mark_chat_put",
    "mark_chat_delete",
]